package joc.internal.transformer;

import javassist.ClassPool;
import javassist.CtBehavior;
import javassist.CtClass;
import javassist.CtMethod;
import joc.BeforeCondition;
import joc.Condition;
import joc.PostCondition;

public class CustomPostConditionBehaviorTransformer extends DeclaredBehaviorTransformer {

	public CustomPostConditionBehaviorTransformer(ClassPool pool) {
		super(pool);
	}

	@Override
	public void transform(CtClass clazz, CtBehavior behavior) throws Exception {
		logger.info("behavior " + behavior.getLongName());
		for (CtBehavior consultedBehavior : getConsultedBehaviors(behavior)) {
			logger.info("consulted behavior " + consultedBehavior.getLongName());
			if (consultedBehavior.hasAnnotation(PostCondition.class)) {
				PostCondition annotation = (PostCondition) consultedBehavior.getAnnotation(PostCondition.class);
				for (Class<?> pcClass : annotation.value()) {
					applyPostCondition(behavior, pcClass.getName());
				}
			}
		}
	}

	private void applyPostCondition(CtBehavior behavior, String pcClassName) throws Exception {
		logger.info("behavior " + behavior.getLongName() + " has post-condition " + pcClassName);
		CtClass annotationClass = pool.get(pcClassName);
		String insertBefore = initializeConditionString(pcClassName);
		String insertAfter = "";
		for (CtMethod pcMethod : annotationClass.getDeclaredMethods()) {
			if (pcMethod.hasAnnotation(BeforeCondition.class) || pcMethod.hasAnnotation(Condition.class)) {
				if (pcMethod.hasAnnotation(BeforeCondition.class)) {
					insertBefore += callConditionString(pcMethod, false, behavior, false);
				} else {
					insertAfter += callConditionString(pcMethod, true, behavior, true);
				}
			}
		}
		logger.info("insertBefore: " + insertBefore);
		logger.info("insertAfter: " + insertAfter);
		insertBefore(behavior, insertBefore);
		insertAfter(behavior, insertAfter);
	}

}
